#!/usr/bin/env python3
"""
qwencode命令行工具的服务包装器
提供异步接口来调用qwencode命令行工具进行文本编码
"""

import asyncio
import os
import sys
import shutil
from typing import Dict, Any, AsyncGenerator, Tuple
import subprocess
import traceback
import time

# 为了处理不同操作系统的兼容性
import platform

# 导入配置文件
from qwencode_config import (
    QWEN_COMMAND, 
    QWEN_COMMAND_ARGS,
    COMMAND_EXECUTION_TIMEOUT,
    COMMAND_VALIDATION_TIMEOUT,
    STREAM_CHUNK_SIZE,
    STREAM_SIMULATION_DELAY,
    WINDOWS_CODEPAGE,
    TIMEOUT_ERROR_MESSAGE,
    TEMP_FILE_PREFIX
)

class QwencodeService:
    def __init__(self):
        """
        初始化qwencode服务
        查找并验证qwencode命令
        """
        self.qwencode_path = self._find_qwencode()
        self._validate_qwencode()
        self.os_type = platform.system()  # 获取操作系统类型
        print(f"✅ qwencode服务已初始化，路径: {self.qwencode_path}")
    
    def _find_qwencode(self) -> str:
        """
        查找qwen命令路径（使用配置中的命令名称）
        """
        # 直接查找qwen命令
        qwen_path = shutil.which(QWEN_COMMAND)
        if qwen_path:
            print(f"✅ 找到{QWEN_COMMAND}命令: {qwen_path}")
            return qwen_path
        
        # 如果找不到命令，抛出异常
        raise FileNotFoundError(f"{QWEN_COMMAND}命令未在系统PATH中找到")
    
    def _validate_qwencode(self) -> None:
        """
        验证qwencode命令是否可用
        """
        try:
            # 构建测试命令 - 只检查版本，不传递复杂参数
            if platform.system() == "Windows":
                # 在Windows上使用PowerShell并绕过执行策略
                # 对于.cmd文件，使用适当的引用方式
                cmd = ["powershell", "-ExecutionPolicy", "Bypass", "&", f'"{self.qwencode_path}" --version']
            else:
                cmd = [self.qwencode_path, "--version"]
            
            print(f"🔍 验证命令: {' '.join(cmd)}")
            
            # 执行测试命令
            result = subprocess.run(
                cmd,
                capture_output=True,
                text=True,
                timeout=COMMAND_VALIDATION_TIMEOUT
            )
            
            # 检查结果
            if result.returncode == 0:
                print(f"✅ qwencode命令验证成功: {self.qwencode_path}")
                print(f"📄 版本信息: {result.stdout.strip()[:100]}")
            else:
                error_msg = result.stderr.strip() if result.stderr else "未知错误"
                print(f"⚠️ qwencode命令验证失败: {error_msg}")
                print(f"ℹ️  标准输出: {result.stdout.strip()[:100] if result.stdout else '无'}")
                # 不抛出异常，继续尝试运行
        except subprocess.TimeoutExpired:
            print(f"⏱️ {QWEN_COMMAND}命令验证超时 (超过{COMMAND_VALIDATION_TIMEOUT}秒)")
            print("ℹ️  这可能是因为命令启动较慢，将继续尝试使用")
        except Exception as e:
            print(f"⚠️ qwencode命令验证过程中出现错误: {str(e)}")
            print(f"📋 详细错误: {traceback.format_exc()}")
            # 继续运行，因为在某些情况下可能需要特定参数才能正常工作
    
    async def _execute_command_simple(self, text: str, working_directory: str = None) -> str:
        """
        简化的命令执行方法，专注于解决中文编码问题
        
        Args:
            text: 要处理的文本
            working_directory: 工作目录，如果提供则在该目录下执行命令
            
        Returns:
            处理后的文本结果
        """
        import subprocess
        import os
        import tempfile
        import asyncio
        import uuid
        
        try:
            print(f"[DEBUG] 使用简化方法执行命令，文本长度: {len(text)}")
            print(f"[DEBUG] 指定工作目录: {working_directory}")
            
            # 验证工作目录是否存在
            cwd = None
            if working_directory:
                if os.path.exists(working_directory):
                    cwd = os.path.abspath(working_directory)
                    print(f"[DEBUG] 验证工作目录存在: {cwd}")
                else:
                    print(f"[WARNING] 指定的工作目录不存在: {working_directory}")
                    print(f"[WARNING] 将使用默认工作目录")
            
            # 生成唯一ID用于临时文件命名
            unique_id = str(uuid.uuid4())[:8]
            
            # 对于Windows系统，使用更简单直接的方法
            if platform.system() == "Windows":
                # 设置环境变量确保UTF-8编码
                env = os.environ.copy()
                env['PYTHONIOENCODING'] = 'utf-8'
                env['LC_ALL'] = 'zh_CN.UTF-8'
                env['LANG'] = 'zh_CN.UTF-8'
                
                # 创建临时目录来存放文件，避免路径问题
                temp_dir = tempfile.gettempdir()
                
                # 创建输入文件
                input_file = os.path.join(temp_dir, f"{TEMP_FILE_PREFIX}input_{unique_id}.txt")
                with open(input_file, 'w', encoding='utf-8') as f:
                    f.write(text)
                
                # 创建批处理文件
                bat_file = os.path.join(temp_dir, f"{TEMP_FILE_PREFIX}run_{unique_id}.bat")
                with open(bat_file, 'w', encoding='utf-8') as f:
                    # 批处理文件内容：设置代码页并执行命令，使用-y参数自动确认
                    f.write(f"@chcp {WINDOWS_CODEPAGE} > nul\n")  # 设置为UTF-8代码页
                    if cwd:
                        f.write(f"@cd \"{cwd}\"\n")  # 切换到指定工作目录
                    f.write(f"@type \"{input_file}\" | \"{self.qwencode_path}\" -y")
                
                print(f"[DEBUG] 创建批处理文件: {bat_file}")
                print(f"[DEBUG] 创建输入文件: {input_file}")
                
                # 在Windows上，我们需要确保路径中的反斜杠不会导致问题
                bat_file = os.path.normpath(bat_file)
                
                # 执行批处理文件
                print(f"[DEBUG] 开始执行命令")
                # 在Windows上使用shell=True以支持管道操作
                result = await asyncio.to_thread(
                    subprocess.run,
                    bat_file,
                    capture_output=True,
                    text=True,
                    encoding='utf-8',
                    errors='replace',
                    env=env,
                    timeout=COMMAND_EXECUTION_TIMEOUT,
                    cwd=cwd,
                    shell=True  # 允许使用shell执行批处理文件
                )
                
                # 清理临时文件
                try:
                    if os.path.exists(input_file):
                        os.unlink(input_file)
                    if os.path.exists(bat_file):
                        os.unlink(bat_file)
                except Exception as cleanup_error:
                    print(f"[WARNING] 清理临时文件失败: {cleanup_error}")
                
                # 检查结果
                if result.returncode != 0:
                    error_msg = result.stderr or f"命令执行失败，退出码: {result.returncode}"
                    print(f"[ERROR] 命令执行失败，退出码: {result.returncode}")
                    print(f"[ERROR] 错误信息: {error_msg}")
                    # 也打印标准输出，因为有些错误可能在stdout中
                    if result.stdout:
                        print(f"[ERROR] 标准输出内容: {result.stdout[:500]}...")
                    raise Exception(error_msg)
                
                # 确保返回正确编码的文本
                print(f"[DEBUG] 命令执行成功，输出长度: {len(result.stdout)}")
                # 确保返回的是UTF-8编码的字符串
                return result.stdout
            else:
                # 非Windows系统的处理
                process = await asyncio.to_thread(
                    subprocess.Popen,
                    [self.qwencode_path] + QWEN_COMMAND_ARGS,  # 使用配置的命令参数
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    text=True,
                    encoding='utf-8',
                    cwd=cwd  # 设置工作目录
                )
                
                stdout, stderr = await asyncio.to_thread(
                    process.communicate,
                    input=text + '\n'
                )
                
                # 检查是否有交互输出
                if "选择" in stdout or "请输入" in stdout or "是否" in stdout:
                    print(f"[INFO] 检测到命令行交互选项:")
                    print(f"[INFO] 交互内容: {stdout}")
                    print(f"[INFO] 注意: 程序自动使用默认选项继续执行")
                
                if process.returncode != 0:
                    error_msg = stderr or "命令执行失败"
                    print(f"[ERROR] 非Windows环境命令执行失败: {error_msg}")
                    raise Exception(error_msg)
                
                return stdout
        except subprocess.TimeoutExpired:
            print(f"[CRITICAL] 命令执行超时，可能是因为等待交互输入")
            # 返回友好的错误消息而不是抛出异常
            return TIMEOUT_ERROR_MESSAGE
        except FileNotFoundError as e:
            print(f"[CRITICAL] 文件未找到错误: {e}")
            raise Exception(f"文件未找到: {e}")
        except PermissionError as e:
            print(f"[CRITICAL] 权限错误: {e}")
            raise Exception(f"权限错误: {e}")
        except Exception as e:
            print(f"[ERROR] 执行命令时出错: {e}")
            import traceback
            print(f"[ERROR] 错误堆栈: {traceback.format_exc()}")
            raise
    
    async def encode_text(
        self,
        text: str,
        encoding_params: Dict[str, Any] = None,
        working_directory: str = None
    ) -> str:
        """
        对文本进行处理
        
        Args:
            text: 要处理的文本
            encoding_params: 处理参数
            working_directory: 工作目录
            
        Returns:
            处理后的文本
        """
        if encoding_params is None:
            encoding_params = {}
        
        print(f"🔄 处理文本: {text[:50]}{'...' if len(text) > 50 else ''}")
        print(f"⚙️  使用参数: {encoding_params}")
        print(f"📂 工作目录: {working_directory}")
        print(f"[DEBUG] 开始编码文本: {text[:50]}...")
        
        # 调用简化的命令执行方法，现在传递working_directory参数
        result = await self._execute_command_simple(text, working_directory)
        
        print(f"[DEBUG] 编码完成，结果长度: {len(result) if result else 0}")
        return result.strip() if result else ""
    
    async def encode_text_stream(
        self,
        text: str,
        encoding_params: Dict[str, Any] = None,
        working_directory: str = None
    ) -> AsyncGenerator[str, None]:
        """
        流式编码文本
        实现真正的流式处理，逐块返回编码结果
        
        Args:
            text: 要编码的文本
            encoding_params: 编码参数
            working_directory: 工作目录
            
        Yields:
            编码后的文本块
        """
        try:
            print(f"🚀 开始流式编码处理...")
            print(f"📂 工作目录: {working_directory}")
            # 对于流式处理，先返回启动信息
            yield "流式处理已启动...\n"
            
            # 调用非流式方法并分块返回结果，传递工作目录参数
            result = await self._execute_command_simple(text, working_directory)
            
            # 模拟流式返回
            chunk_size = STREAM_CHUNK_SIZE
            total_chunks = (len(result) + chunk_size - 1) // chunk_size
            for i in range(0, len(result), chunk_size):
                chunk = result[i:i+chunk_size]
                # 打印流式效果到控制台
                chunk_progress = (i // chunk_size) + 1
                chunk_display = chunk[:30] + ('...' if len(chunk) > 30 else '')
                print(f"[流式输出 {chunk_progress}/{total_chunks}] 块大小: {len(chunk)}, 内容: {chunk_display}")
                
                yield chunk
                # 模拟延迟
                await asyncio.sleep(STREAM_SIMULATION_DELAY)
            
            print(f"✅ 流式编码完成，总共 {total_chunks} 个块")
        except Exception as e:
            print(f"❌ 流式编码异常: {str(e)}")
            print(f"📋 异常详情: {traceback.format_exc()}")
            # 抛出异常让调用者处理
            raise


        
if __name__ == "__main__":
    # 主入口提示
    print("请使用 qwencode_api.py 启动完整的API服务")
    print("或使用 qwencode_api_client.py 连接到已运行的API服务")